package com.ngc.mall.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ngc.mall.bo.OrderSku;
import com.ngc.mall.common.configure.LocalUser;
import com.ngc.mall.common.configure.exception.BusinessException;
import com.ngc.mall.common.configure.mybatisPlus.BaseServiceImpl;
import com.ngc.mall.common.configure.response.ResponseCode;
import com.ngc.mall.core.enumeration.DateType;
import com.ngc.mall.core.enumeration.OrderStatus;
import com.ngc.mall.core.enumeration.PayType;
import com.ngc.mall.core.enumeration.PlatformType;
import com.ngc.mall.core.money.IMoneyDiscount;
import com.ngc.mall.domain.CouponDomain;
import com.ngc.mall.domain.OrderDomain;
import com.ngc.mall.domain.SkuDomain;
import com.ngc.mall.domain.UserCouponDomain;
import com.ngc.mall.dto.DeliveryDTO;
import com.ngc.mall.dto.OrderDTO;
import com.ngc.mall.dto.OrderFilterDTO;
import com.ngc.mall.logic.CouponChecker;
import com.ngc.mall.logic.OrderChecker;
import com.ngc.mall.mapper.OrderMapper;
import com.ngc.mall.service.ICouponService;
import com.ngc.mall.service.IOrderService;
import com.ngc.mall.service.ISkuService;
import com.ngc.mall.service.IUserCouponService;
import com.ngc.mall.util.CommonUtil;
import com.ngc.mall.util.OrderUtil;
import com.ngc.mall.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 *  订单实现类
 *
 * @author : Chen Xiao Lin
 * @Date : 2023/5/5 17:45
 **/

@Service
public class OrderServiceImpl extends BaseServiceImpl<OrderMapper, OrderDomain> implements IOrderService {

    @Resource
    private ISkuService iSkuService;


    @Resource
    private ICouponService iCouponService;

    @Resource
    private IUserCouponService iUserCouponService;

    private IMoneyDiscount iMoneyDiscount;

    @Value("${wechat.sku.max-limit}")
    private Integer maxLimitCount;

    @Value("${wechat.order.pay-time-limit}")
    private Integer payTimeLimit;

    @Value("${wechat.order.receive-time-limit}")
    private Integer receiveTimeLimit;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;


    @Override
    @Transactional
    public Long createOrder(OrderDTO orderDTO,Long uid,OrderChecker orderChecker) {
        Calendar now=Calendar.getInstance();
        Calendar now1=(Calendar) now.clone();
        OrderDomain orderDomain= OrderDomain.builder()
                .userId(uid)
                .orderNo(OrderUtil.makeOrderNo())
                .placedTime(now.getTime())
                .expireTime(CommonUtil.addSomeSeconds(now1,this.payTimeLimit).getTime())
                .sourceType(orderDTO.getSourceType())
                .payType(orderDTO.getPayType())
                .totalAmount(orderDTO.getTotalAmount())
                .totalCount(orderChecker.getTotalCount())
                .finalPayAmount(orderDTO.getFinalPayAmount())
                .status(OrderStatus.UNPAID.getValue())
                .note(orderDTO.getNote())
                .snapImg(orderChecker.getLeaderImg())
                .snapTitle(orderChecker.getLeaderTitle())
                .build();
        orderDomain.setSnapAddress(orderDTO.getOrderAddressDTO());
        orderDomain.setSnapItems(orderChecker.getOrderSkuList());
        Long oid=super.create(orderDomain);
        this.reduceSkuStock(orderChecker);
        Long couponId = -1L;
        if(orderDTO.getCouponId()!=null){
            CouponDomain coupon=iCouponService.findById(orderDTO.getCouponId());
            this.writeOffCoupon(coupon,uid,oid);
            couponId=orderDTO.getCouponId();
        }
        this.sendToRedis(couponId,oid,uid);
        return oid;
    }

    public void reduceSkuStock(OrderChecker orderChecker){
        List<OrderSku> orderSkuList=orderChecker.getOrderSkuList();
        for(OrderSku orderSku:orderSkuList){
           Boolean isReduce=iSkuService.reduceSkuStock(orderSku.getId(),orderSku.getCount());
            if(!isReduce){
                System.out.println("减少库存错误");
//                throw new BusinessException();
            }
        }
    }

    public void sendToRedis(Long couponId,Long oid,Long uid){
        String key = couponId.toString() + "," + oid.toString() + "," + uid.toString();

        try {
            stringRedisTemplate.opsForValue().set(key, "1", this.payTimeLimit, TimeUnit.SECONDS);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void sendToRedisReceived(Long oid,Long uid){
        String key=oid+","+uid;
        stringRedisTemplate.opsForValue().set(key,"2", this.receiveTimeLimit,TimeUnit.SECONDS);
    }

    public void writeOffCoupon(CouponDomain coupon,Long userId,Long orderId){
        Boolean result=iUserCouponService.writeOff(coupon,userId,orderId);
        if(!result){
            System.out.println("核销优惠券失败");
        }
    }

    @Override
    public OrderChecker isOk(OrderDTO orderDTO,Long userId){
        Long couponId=orderDTO.getCouponId();
        CouponChecker couponChecker=null;
        if(orderDTO.getCouponId()!=null){
            CouponDomain couponDomain=iCouponService.findById(couponId);
            couponDomain.setCategoryList(iCouponService.findCategoriesById(couponId));
            if(couponDomain==null){
                throw new BusinessException(ResponseCode.COUPON_NOT_EXIST);
            }
            UserCouponDomain userCouponDomain=iUserCouponService.getOne(Wrappers.<UserCouponDomain>lambdaQuery().eq(UserCouponDomain::getUserId,userId).eq(UserCouponDomain::getCouponId,couponId));
            if(userCouponDomain==null){
                throw  new BusinessException(ResponseCode.USER_COUPON_NOT_EXIST);
            }
            couponChecker=new CouponChecker(couponDomain,iMoneyDiscount);
        }
        List<Long> skuIdList= orderDTO.getSkuInfoDTOList().stream().map(sku->sku.getId()).collect(Collectors.toList());
        List<SkuDomain> skuDomainList=iSkuService.findByIdList(skuIdList);
        OrderChecker orderChecker= new OrderChecker(orderDTO,couponChecker,skuDomainList,maxLimitCount);
        orderChecker.isOk();
        return orderChecker;
    }

    @Override
    public void cancel(Long oid) {
        Boolean cancelResult=super.update(Wrappers.<OrderDomain>lambdaUpdate().eq(OrderDomain::getId,oid).eq(OrderDomain::getStatus,OrderStatus.UNPAID.getValue()).set(OrderDomain::getStatus,OrderStatus.CANCELED.getValue()));
        if(!cancelResult){
            System.out.println("取消订单失败");
        }
        OrderDomain orderDomain=this.getOrderDetailById(oid);
        orderDomain.getSnapItems().forEach((item)->{
           iSkuService.recoverStock(item);
        });
    }

    @Override
    public OrderDomain getOrderDetailById(Long id) {
        return super.getById(id);
    }

    @Override
    public PagingVO<OrderDomain> search(OrderFilterDTO dto, int start, int count) {
        Page<OrderDomain> page=new Page<>(start,count);
        LambdaQueryWrapper<OrderDomain> queryWrapper=Wrappers.<OrderDomain>lambdaQuery().orderByDesc(OrderDomain::getCreateTime);
        if(StringUtils.isNotBlank(dto.getOrderNo())){
            queryWrapper.like(OrderDomain::getOrderNo,dto.getOrderNo());
        }
        if(dto.getSourceType()!=PlatformType.ALL.getValue()){
            queryWrapper.eq(OrderDomain::getSourceType,dto.getSourceType());
        }
        if(dto.getPayType()!=PayType.ALL.getValue()){
            queryWrapper.eq(OrderDomain::getPayType,dto.getPayType());
        }
        if(dto.getStatus()!=OrderStatus.ALL.getValue()){
            queryWrapper.eq(OrderDomain::getStatus,dto.getStatus());
        }
        if(StringUtils.isNotBlank(dto.getUserPhone())){
            queryWrapper.apply("JSON_EXTRACT(snap_address, '$.mobile') = {0}", dto.getUserPhone());
        }

        if(Optional.ofNullable(dto.getStartDate()).isPresent()&&Optional.ofNullable(dto.getEndDate()).isPresent()){
            queryWrapper.ge(OrderDomain::getCreateTime,dto.getStartDate()).le(OrderDomain::getCreateTime,dto.getEndDate());
        }
        IPage iPage=super.page(page,queryWrapper);
        PagingVO<OrderDomain> pagingVO=new PagingVO<>(iPage);
        return pagingVO;
    }

    @Override
    public PagingVO getMySelfByStatus(int status, int start, int count) {
        Long uid= LocalUser.getUser().getId();
        Page<OrderDomain> page=new Page<>(start,count);
        if(status==OrderStatus.ALL.getValue()){
            return this.getMySelfAllById(uid,page,start,count);
        }
        IPage iPage= super.page(page,Wrappers.<OrderDomain>lambdaQuery().eq(OrderDomain::getUserId,uid).eq(OrderDomain::getStatus,status).orderByDesc(OrderDomain::getCreateTime));
        PagingVO<OrderDomain> pagingVO=new PagingVO<>(iPage);
        return pagingVO;

    }

    @Override
    public PagingVO getByStatus(int status, int start, int count) {
        Page<OrderDomain> page=new Page<>(start,count);
        LambdaQueryWrapper<OrderDomain> wrapper;
        if(status==OrderStatus.ALL.getValue()){
            wrapper=Wrappers.<OrderDomain>lambdaQuery().orderByDesc(OrderDomain::getCreateTime);
        }else{
            wrapper=Wrappers.<OrderDomain>lambdaQuery().eq(OrderDomain::getStatus,status).orderByDesc(OrderDomain::getCreateTime);
        }
        IPage iPage= super.page(page,wrapper);
        List<OrderDomain> orderList=iPage.getRecords();
        PagingVO<OrderDomain> pagingVO=new PagingVO<>(iPage);
        return pagingVO;
    }

    public PagingVO<OrderDomain> getMySelfAllById(Long uid,Page<OrderDomain> page,int start,int count){
        IPage iPage= super.page(page,Wrappers.<OrderDomain>lambdaQuery().eq(OrderDomain::getUserId,uid).orderByDesc(OrderDomain::getCreateTime));
        List<OrderDomain> orderList=iPage.getRecords();
        PagingVO<OrderDomain> pagingVO=new PagingVO<>(iPage);
        return pagingVO;
    }

    @Override
    public Boolean updateStatusToDelivered(Long oid,DeliveryDTO deliveryDTO){
        OrderDomain orderDomain=getById(oid);
        if(orderDomain==null){
            throw  new BusinessException(ResponseCode.ORDER_NO_EXIST);
        }
        LocalDateTime now=LocalDateTime.now();
        ///按状态/交易id？
        Boolean result=super.update(Wrappers.<OrderDomain>lambdaUpdate().eq(OrderDomain::getId,oid).eq(OrderDomain::getStatus,OrderStatus.PAID.getValue()).set(OrderDomain::getDeliverySn,deliveryDTO.getDeliverySn()).set(OrderDomain::getDeliveryCompany,deliveryDTO.getDeliveryCompany()).set(OrderDomain::getStatus,OrderStatus.DELIVERED.getValue()).set(OrderDomain::getDeliveryTime,now));

        this.sendToRedisReceived(oid, orderDomain.getUserId());
        return result;
    }

    @Override
    public Boolean updateStatusToReceive(Long uid,Long oid){
        OrderDomain orderDomain=getById(oid);
        if(orderDomain==null){
            throw  new BusinessException(ResponseCode.ORDER_NO_EXIST);
        }
        LocalDateTime now=LocalDateTime.now();
        return super.update(Wrappers.<OrderDomain>lambdaUpdate().eq(OrderDomain::getId,oid).eq(OrderDomain::getUserId,uid).eq(OrderDomain::getStatus,OrderStatus.DELIVERED.getValue()).set(OrderDomain::getStatus,OrderStatus.FINISHED.getValue()).set(OrderDomain::getReceiveTime,now));
    }

    @Override
    public OrderCountVO getMyOrderCountByStatus(Long uid){
        int unpaidCount=super.count(Wrappers.<OrderDomain>lambdaQuery().eq(OrderDomain::getStatus,OrderStatus.UNPAID.getValue()).eq(OrderDomain::getUserId,uid));
        int paidCount=super.count(Wrappers.<OrderDomain>lambdaQuery().eq(OrderDomain::getStatus,OrderStatus.PAID.getValue()).eq(OrderDomain::getUserId,uid));
        int deliveredCount=super.count(Wrappers.<OrderDomain>lambdaQuery().eq(OrderDomain::getStatus,OrderStatus.DELIVERED.getValue()).eq(OrderDomain::getUserId,uid));
       OrderCountVO orderCountVO=OrderCountVO.builder().unpaidCount(unpaidCount).paidCount(paidCount).deliveredCount(deliveredCount).afterSaleCount(0).build();
       return orderCountVO;
    }

    @Override
    public OrderOverviewVO getOrderOverview() {
        int unPaidOrderCount=super.count(Wrappers.<OrderDomain>lambdaQuery().eq(OrderDomain::getStatus,OrderStatus.UNPAID.getValue()));
        int paidOrderCount=super.count(Wrappers.<OrderDomain>lambdaQuery().eq(OrderDomain::getStatus,OrderStatus.PAID.getValue()));
        int deliveredOrderCount=super.count(Wrappers.<OrderDomain>lambdaQuery().eq(OrderDomain::getStatus,OrderStatus.DELIVERED.getValue()));
        int afterSaleOrderCount=super.count(Wrappers.<OrderDomain>lambdaQuery().eq(OrderDomain::getStatus,OrderStatus.AFTERSALE.getValue()));
        return OrderOverviewVO.builder().unPaidOrderCount(unPaidOrderCount).paidOrderCount(paidOrderCount).deliveredOrderCount(deliveredOrderCount).afterSaleOrderCount(afterSaleOrderCount).build();
    }

    @Override
    public OrderSummaryVO queryOrderByDateRange(String startDate, String endDate) {

        return OrderSummaryVO.builder().build();
    }

    public OrderReportSummaryVO queryOrderReportToday(){
//        ///当前时间，显示数据更新时刻
//        LocalDateTime now=LocalDateTime.now();
//        ///今天是2023-10-09
//        String date=now.format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
        ///今天销售额，销售数
        OrderSummaryVO todayOrderSummary=baseMapper.queryToday();
        ///昨天销售额，销售数
        OrderSummaryVO ydayOrderSummary=baseMapper.queryYesterday();
        BigDecimal d = todayOrderSummary.getTotalAmount().subtract(ydayOrderSummary.getTotalAmount());
        BigDecimal s = ydayOrderSummary.getTotalAmount();
        BigDecimal amountRate;
        if ((BigDecimal.ZERO).compareTo(s) == 0 ) {
            System.out.println(d);
            amountRate=new BigDecimal(String.valueOf(0));
        }else{
            BigDecimal divide = d.divide(s,BigDecimal.ROUND_HALF_UP);
            System.out.println(divide);
            amountRate=new BigDecimal(String.valueOf(divide));
        }
//        BigDecimal amountRate=(todayOrderSummary.getTotalAmount().subtract(ydayOrderSummary.getTotalAmount()).divide(ydayOrderSummary.getTotalAmount(), 2));
        ///0-24时的销售情况
        List<OrderSummaryVO> todayForHourOrderSummary=baseMapper.queryTodayForHour();

        OrderReportSummaryVO orderReportSummaryVO= OrderReportSummaryVO.builder().totalAmount(todayOrderSummary.getTotalAmount()).totalCount(todayOrderSummary.getTotalCount()).amountRate(amountRate).lastTotalAmount(ydayOrderSummary.getTotalAmount()).lastTotalCount(ydayOrderSummary.getTotalCount()).orderSummaryList(todayForHourOrderSummary).build();
        System.out.println(orderReportSummaryVO);
        return orderReportSummaryVO;
    }

    public OrderReportSummaryVO queryOrderReportMonth(){

        // 本月销售额，销售数
        OrderSummaryVO monthOrderSummary=baseMapper.queryMonth();
        ///上个月销售额，销售数
        OrderSummaryVO lastMonthOrderSummary=baseMapper.queryLastMonth();
        ///本月每天的销售情况
        List<OrderSummaryVO> monthForDateOrderSummary=baseMapper.queryMonthForDay();

        OrderReportSummaryVO orderReportSummaryVO= OrderReportSummaryVO.builder().totalAmount(monthOrderSummary.getTotalAmount()).totalCount(monthOrderSummary.getTotalCount()).lastTotalAmount(lastMonthOrderSummary.getTotalAmount()).lastTotalCount(lastMonthOrderSummary.getTotalCount()).orderSummaryList(monthForDateOrderSummary).build();
        return orderReportSummaryVO;
    }

    public OrderReportSummaryVO queryOrderReportQuarter(){
        ///当前是一年的第几季度

        ///本季度的销售数，销售额
        OrderSummaryVO quarterOrderSummary=baseMapper.queryQuarter();
        ///上季度的销售数，销售额
        OrderSummaryVO lastQuarterOrderSummary=baseMapper.queryLastQuarter();
        ///该季度每天的销售额，销售数
        List<OrderSummaryVO> monthForQuarterOrderSummary=baseMapper.queryQuarterForMonth();
        OrderReportSummaryVO orderReportSummaryVO= OrderReportSummaryVO.builder().totalAmount(quarterOrderSummary.getTotalAmount()).totalCount(quarterOrderSummary.getTotalCount()).lastTotalAmount(lastQuarterOrderSummary.getTotalAmount()).lastTotalCount(lastQuarterOrderSummary.getTotalCount()).orderSummaryList(monthForQuarterOrderSummary).build();
        return orderReportSummaryVO;
    }

    public OrderReportSummaryVO queryOrderReportWeek(){
        ///本周销售额/
        OrderSummaryVO weekOrderSummary=baseMapper.queryWeek();
        System.out.println(weekOrderSummary);

        ///上周销售额，销售数
        OrderSummaryVO lastWeekOrderSummary=baseMapper.queryLastWeek();
        System.out.println(lastWeekOrderSummary);

        BigDecimal amountRate=(weekOrderSummary.getTotalAmount().subtract(lastWeekOrderSummary.getTotalAmount()).divide(lastWeekOrderSummary.getTotalAmount(),2));

        ///本周每天的销售额，销售数
        List<OrderSummaryVO> weekForDateOrderSummary=baseMapper.queryWeekForDay();
        OrderReportSummaryVO orderReportSummaryVO= OrderReportSummaryVO.builder().totalAmount(weekOrderSummary.getTotalAmount()).totalCount(weekOrderSummary.getTotalCount()).amountRate(amountRate).lastTotalAmount(lastWeekOrderSummary.getTotalAmount()).lastTotalCount(lastWeekOrderSummary.getTotalCount()).orderSummaryList(weekForDateOrderSummary).build();
        return orderReportSummaryVO;
    }

    public OrderReportSummaryVO queryOrderReportYear(){
        ///今年年份

        //今年销售额，销售数
        OrderSummaryVO yearOrderSummary=baseMapper.queryYear();
        //去年销售额，销售数
        OrderSummaryVO lastYearOrderSummary=baseMapper.queryLastYear();
        //1-12个月分别的销售额，销售数
        List<OrderSummaryVO> yearForMonthOrderSummary=baseMapper.queryYearForMonth();

        OrderReportSummaryVO orderReportSummaryVO= OrderReportSummaryVO.builder().totalAmount(yearOrderSummary.getTotalAmount()).totalCount(yearOrderSummary.getTotalCount()).lastTotalAmount(lastYearOrderSummary.getTotalAmount()).lastTotalCount(lastYearOrderSummary.getTotalCount()).orderSummaryList(yearForMonthOrderSummary).build();
        return orderReportSummaryVO;
    }

    @Override
    public OrderReportSummaryVO queryOrderByDateType(int type) {
        LocalDateTime now=LocalDateTime.now();
        ///今天是2023-10-09
        String date=now.format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
        int year=now.getYear();
        int month=now.getMonthValue();
        int week=now.getDayOfWeek().getValue();
        int quarter= (int) Math.floor((month % 3 == 0 ? (month / 3) : (month / 3 + 1)));
        OrderReportSummaryVO vo= OrderReportSummaryVO.builder().build();
        switch (DateType.toType(type)){
            case DAY:
                vo=queryOrderReportToday();
                break;
            case WEEK:
                vo=queryOrderReportWeek();
                break;
            case MONTH:
                vo=queryOrderReportMonth();
                break;
            case QUARTER:
                vo=queryOrderReportQuarter();
                break;
            case YEAR:
                vo=queryOrderReportYear();
                break;
            default:
                throw BusinessException.FAILURE;
        }
        vo.setDate(date);
        vo.setMonth(month);
        vo.setYear(year);
        vo.setWeek(week);
        vo.setQuarter(quarter);
        vo.setQueryTime(now);
        return vo;
    }

    @Override
    public List<OrderDomain> getOrderByMemberId(Long memberId) {
        return super.list(Wrappers.<OrderDomain>lambdaQuery().eq(OrderDomain::getUserId,memberId).orderByDesc(OrderDomain::getCreateTime));
    }
}
